package mdc485

import (
	"encoding/hex"
	"fmt"
	"strconv"
	"testCOM/mdc485/define"
	"testCOM/mdc485/helper"
)

//CommonPack source是除去校验位和结束位的原始数据（开始位+地址位+指令+数据）
func CommonPack(source []byte) []byte {
	//在特殊字节前面插入0x10
	target := addPrefix2SpecialByte(source)

	//生成校验位
	cs, err := helper.GenerateCheckXOR(target)
	if err != nil {

		return nil
	}
	//如果校验位也是特殊字节，也插入0x10
	if isSpecialByte(cs) {
		target = append(target, define.Inst)
	}
	target = append(target, cs)

	return target
}

func isSpecialByte(b byte) bool {
	var isSpecial bool
	switch b {
	case define.SPECIAL_BYTES_STX, define.SPECIAL_BYTES_ETX, define.SPECIAL_BYTES_RESP_SUCCESS, define.SPECIAL_BYTES_INST, define.SPECIAL_BYTES_RESP_FAIL, define.SPECIAL_BYTES_16:
		isSpecial = true
	default:

	}
	return isSpecial
}

func addPrefix2SpecialByte(source []byte) []byte {
	var result []byte
	//开始位不进行特殊字节判断
	result = append(result, source[0])
	for i := 1; i < len(source); i++ {
		if isSpecialByte(source[i]) {
			result = append(result, define.Inst)
		}
		result = append(result, source[i])
	}
	return result
}

//
func Int16ToByte(data int) []byte {
	target := make([]byte, 2)
	uData := uint16(data)
	target[0] = byte(uData)
	target[1] = byte(uData >> 8)
	return target
}

//解析协议数据
func DecodeProto(data []byte, cmd string) {
	switch cmd {
	case "status":
		DeGetStatus(data)
		break
	case "setControl":

		break
	default:

	}
}

//组包协议数据
func EncodeProto(cmd string, add int, data *[]byte) {
	switch cmd {
	case "status":
		err := GetStatus(add, data)
		if err != nil {
			fmt.Printf("mdc485 status create fail:%s\n", err.Error())
			return
		}
		break
	case "setControl":
		err := SetControl(add, data)
		if err != nil {
			fmt.Printf("mdc485 status create fail:%s\n", err.Error())
			return
		}
		break
	default:
		fmt.Printf("mdc485 ProtoCmd:%s not support\n", cmd)
		return
	}
}

//取状态
func GetStatus(add int, data *[]byte) error {
	*data = append(*data, define.STX, byte(add), byte(define.CMD_GET_STATUS))
	*data = append(*data, 0x00, 0x00) //备用
	*data = CommonPack(*data)
	*data = append(*data, define.ETX)
	return nil
}

//解析取状态
func DeGetStatus(data []byte) error {
	if data[2] == byte(define.CMD_GET_STATUS) && len(data) > 11 {
		fmt.Printf("【<<<收到mdc485取状态结果】：")
		fmt.Printf("\n\t记录标识符[0x%02x]:", data[3])
		if data[3] == 0 {
			fmt.Printf("无记录")
		} else {
			if data[3]&0x08 == 0x08 {
				fmt.Printf(" 刷卡记录")
			}
			if data[3]&0x10 == 0x10 {
				fmt.Printf(" 报警记录")
			}
			if data[3]&0x20 == 0x20 {
				fmt.Printf(" 卡状态记录")
			}
		}
		fmt.Printf("\n\t门开关状态[0x%02x]: %v", data[5], strconv.FormatInt(int64(data[5]), 2))
		fmt.Printf("\n\t继电器状态[0x%02x]: %v", data[6], strconv.FormatInt(int64(data[6]), 2))
		fmt.Printf("\n\t控制器版本[0x%02x]: %d", data[7], data[7])
		fmt.Printf("\n\tOEM代码[0x%02x%02x]: %d", data[8], data[9], ((int(data[8]) << 8) + int(data[9])))
		fmt.Printf("\n\t功能控制位[0x%02x]:", data[10])
		if data[10]&0x01 == 0x01 {
			fmt.Printf(" 截止日期")
		}
		if data[10]&0x02 == 0x02 {
			fmt.Printf(" OEM专属")
		}
		if data[10]&0x04 == 0x04 {
			fmt.Printf(" 卡携带姓名")
		}
		if data[10]&0x10 == 0x10 {
			fmt.Printf(" 4字节密码")
		}
		fmt.Printf("\n")
	}
	return nil
}

//设置控制器参数
func SetControl(add int, data *[]byte) error {
	*data = append(*data, define.STX, byte(add), byte(define.CMD_SET_CONTROLLER_PARAM))
	*data = append(*data, 0x00)                //互锁设置  0:没有互锁， 1: 1-2门互锁  2:3-4门互锁
	*data = append(*data, Int16ToByte(180)...) //火警输出时间长度。低位在前，高位在后
	*data = append(*data, Int16ToByte(180)...) //警报输出时间长度。低位在前，高位在后
	passWord, _ := hex.DecodeString("85543889")
	*data = append(*data, passWord...) //V2挟持密码，BCD编码  V1 整数，高位在前
	*data = CommonPack(*data)
	*data = append(*data, define.ETX)
	return nil
}
